package top.guoziyang.mydb.backend.vm;

import java.util.Arrays;

import com.google.common.primitives.Bytes;

import top.guoziyang.mydb.backend.common.SubArray;
import top.guoziyang.mydb.backend.dm.dataItem.DataItem;
import top.guoziyang.mydb.backend.utils.Parser;

/**
 * VM向上层抽象出entry
 * entry结构：
 * [XMIN] [XMAX] [data]
 */
public class Entry {

    private static final int OF_XMIN = 0;
    private static final int OF_XMAX = OF_XMIN+8;
    private static final int OF_DATA = OF_XMAX+8;

    private long uid;
    private DataItem dataItem;
    private VersionManager vm;

    /**
     *  创建并返回一个新的Entry实例
     */
    public static Entry newEntry(VersionManager vm, DataItem dataItem, long uid) {
        if (dataItem == null) {
            return null;
        }
        Entry entry = new Entry();
        entry.uid = uid;
        entry.dataItem = dataItem;
        entry.vm = vm;
        return entry;
    }

    /**
     *  读取指定uid的DataItem，并通过newEntry创建相应的Entry对象
     */
    public static Entry loadEntry(VersionManager vm, long uid) throws Exception {
        DataItem di = ((VersionManagerImpl)vm).dm.read(uid);
        return newEntry(vm, di, uid);
    }

    /**
     *  封装新Entry的字节结构
     */
    public static byte[] wrapEntryRaw(long xid, byte[] data) {
        byte[] xmin = Parser.long2Byte(xid);
        byte[] xmax = new byte[8]; // 初始化为0
        return Bytes.concat(xmin, xmax, data);
    }

    /**
     *  释放Entry资源，由VersionManager负责处理
     */
    public void release() {
        ((VersionManagerImpl)vm).releaseEntry(this);
    }

    /**
     *  释放dataItem资源
     */
    public void remove() {
        dataItem.release();
    }

    /**
     *  读取并返回Entry的数据内容,以字节数组形式复制返回dataItem的数据部分
     */
    public byte[] data() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            byte[] data = new byte[sa.end - sa.start - OF_DATA];
            System.arraycopy(sa.raw, sa.start+OF_DATA, data, 0, data.length);
            return data;
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     *  获取当前Enrty的起始事务ID。
     *  在数据库系统中，使用XMIN和XMAX来标记记录的创建和删除事务是常见的设计模式，XMIN作为记录的创建事务ID，其固定位置通常是记录起始位置的第一个字段。
     *  DataItem结构：[ValidFlag] [DataSize] [Data]  Entry结构：[XMIN] [XMAX] [data]
     *  DataItem整体结构其实为： [ValidFlag] [DataSize] [【[XMIN] [XMAX] [data]】]
     */
    public long getXmin() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            return Parser.parseLong(Arrays.copyOfRange(sa.raw, sa.start+OF_XMIN, sa.start+OF_XMAX));
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     *  获取当前Enrty的删除事务ID。
     */
    public long getXmax() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            return Parser.parseLong(Arrays.copyOfRange(sa.raw, sa.start+OF_XMAX, sa.start+OF_DATA));
        } finally {
            dataItem.rUnLock();
        }
    }

    /**
     *  修改 Entry 记录的删除事务 ID（初始时为0）
     */
    public void setXmax(long xid) {
        // 修改之前对数据进行备份，方便需要时回滚
        dataItem.before();
        try {
            SubArray sa = dataItem.data();
            // 将删除事务的id写入DataItem中
            System.arraycopy(Parser.long2Byte(xid), 0, sa.raw, sa.start+OF_XMAX, 8);
        } finally {
            // 修改后，生成对应的日志，记录这次对XMAX的修改操作
            dataItem.after(xid);
        }
    }

    public long getUid() {
        return uid;
    }
}
